//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2014 leishangwen@163.com                       ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Module:  div
// File:    div.v
// Author:  Lei Silei
// E-mail:  leishangwen@163.com
// Description: ����ģ��
// Revision: 1.0
//////////////////////////////////////////////////////////////////////

// `include "defines.vh"

`define ZeroWord 32'h00000000

`define DivResultNotReady 1'b0
`define DivResultReady 1'b1

`define DivStart 1'b1
`define DivStop 1'b0

`define RstEnable 1'b1

`define DivFree 2'b00
`define DivByZero 2'b01
`define DivOn 2'b10
`define DivEnd 2'b11

module div (
    input wire clk,
    input wire rst,

    input wire        signed_div_i,  // 是否是有符号除法
    input wire [31:0] opdata1_i,     // 除数
    input wire [31:0] opdata2_i,     // 被除数
    input wire        start_i,       // 开始信号
    input wire        annul_i,       // 终止信号

    // output reg [63:0] result_o,  // 结果
    output reg [31:0] hi,
    lo,
    output reg div_running  // 结果就绪信号，如果当前result_o是计算完成的结果，置1
);

  wire [32:0] div_temp;  // 中间结果临时变量
  reg  [ 5:0] cnt;  // 计数器
  reg  [64:0] dividend;  // 被除数拓展位65位
  reg  [ 1:0] state;  // 状态机
  reg  [31:0] divisor;  // 除数
  reg  [31:0] temp_op1;
  reg  [31:0] temp_op2;

  reg [31:0] tmp_1, tmp_2;

  reg sign_op1, sign_op2;  // 记录符号

  assign div_temp = {1'b0, dividend[63:32]} - {1'b0, divisor};

  always @(posedge clk) begin
    if (rst == `RstEnable) begin
      state <= `DivFree;
      div_running <= 1'b0;
      hi <= `ZeroWord;
      lo <= `ZeroWord;
    end else begin
      case (state)
        `DivFree: begin  //DivFree 空闲状态
          div_running <= 1'b0;
          if (start_i == `DivStart && annul_i == 1'b0) begin
            if (opdata2_i == `ZeroWord) begin
              state <= `DivByZero;
            end else begin
              state <= `DivOn;
              cnt <= 6'b000000;
              sign_op1 <= opdata1_i[31];
              sign_op2 <= opdata2_i[31];
              // 如果是有符号除法，则对原操作数进行取反加一
              if (signed_div_i == 1'b1 && opdata1_i[31] == 1'b1) begin
                temp_op1 = ~opdata1_i + 1;
              end else begin
                temp_op1 = opdata1_i;
              end
              // 如果是有符号除法，则对原操作数进行取反加一
              if (signed_div_i == 1'b1 && opdata2_i[31] == 1'b1) begin
                temp_op2 = ~opdata2_i + 1;
              end else begin
                temp_op2 = opdata2_i;
              end
              // 初始化65位的dividend，这是被除数的扩展
              dividend <= {`ZeroWord, `ZeroWord};
              // 离最低位差一位，方便第一次循环
              dividend[32:1] <= temp_op1;
              // 初始化divisor为除数
              divisor <= temp_op2;
            end
          end else begin
            hi <= `ZeroWord;
            lo <= `ZeroWord;
          end
        end
        `DivByZero: begin  //DivByZero
          div_running <= 1'b1;
          dividend <= {`ZeroWord, `ZeroWord};
          state <= `DivEnd;
        end
        `DivOn: begin  //DivOn
          div_running <= 1'b1;
          if (annul_i == 1'b0) begin
            if (cnt != 6'b100000) begin
              // dividend高32位 < divisor
              if (div_temp[32] == 1'b1) begin
                // 左移，低位置0
                dividend <= {dividend[63:0], 1'b0};
              end else begin
                dividend <= {div_temp[31:0], dividend[31:0], 1'b1};
              end
              cnt <= cnt + 1;
            end else begin
              if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
                dividend[31:0] <= (~dividend[31:0] + 1);
              end
              if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
                dividend[64:33] <= (~dividend[64:33] + 1);
              end
              state <= `DivEnd;
              cnt   <= 6'b000000;
            end
          end else begin
            state <= `DivFree;
          end
        end
        `DivEnd: begin  //DivEnd
          div_running <= 1'b1;
          // if (signed_div_i) begin
          //   //决定余数的符号
          //   tmp_1 <= dividend[64:33];
          //   hi <= sign_op2 ? tmp_1 : ~tmp_1 + 1;
          //   // 决定商的符号
          //   tmp_2 <= dividend[31:0];
          //   lo <= (sign_op1 ^ sign_op2) ? tmp_2 : ~tmp_2 + 1;

          // end else begin

          // end
          tmp_1 <= dividend[64:33];
          tmp_2 <= dividend[31:0];

          if (signed_div_i) begin
            //决定余数的符号
            hi <= sign_op2 ? dividend[64:33] : ~dividend[64:33] + 1;
            // 决定商的符号
            lo <= (sign_op1 ^ sign_op2) ? ~dividend[31:0] + 1 : dividend[31:0];
          end else begin
            hi <= dividend[64:33];
            lo <= dividend[31:0];
          end
          state <= `DivFree;
        end
      endcase
    end
  end

endmodule
